defmodule Iocp.Receiver do
  @moduledoc false

  use Bitwise

  @packet_start [0x68, 0x16]

  def receive(client, device_address) do
    {:ok, @packet_start} = :gen_tcp.recv(client, 2)
    {:ok, [lo, hi]} = :gen_tcp.recv(client, 2)
    {:ok, data_and_checksum} = :gen_tcp.recv(client, (hi <<< 8) ||| lo)
    {:ok, pid} = Task.Supervisor.start_child(Iocp.Task.Supervisor, fn ->
      [checksum | data] = Enum.reverse(data_and_checksum)
      data = Enum.reverse(data)
      validate_checksum!([@packet_start, [lo, hi], data], checksum)
      Iocp.Router.dispatch(data, device_address)
    end)
    Process.link(pid)
    receive(client, device_address)
  end

  defp validate_checksum!(data, checksum) do
    ^checksum = data
                |> Stream.flat_map(& &1)
                |> Enum.sum()
                |> Bitwise.&&&(0xFF)
  end

end
